﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

namespace MongoScienceDAL.Core
{
    public class CollectionTypeCreationHelper
    {
        private readonly IDataSource _dataSource;
        private readonly string _collectionName;
        private readonly string _creatingUser;
        private readonly DateTime _currentDate;

        public CollectionTypeCreationHelper(IDataSource dataSource, string collectionName, string creatingUser)
        {
            _dataSource = dataSource;
            _collectionName = collectionName;
            _creatingUser = creatingUser;
            _currentDate = DateTime.Now;
        }

        public CollectionTypeCreationHelper AddText(string name, string key, string description, bool isHidden, bool isRequired, bool isReadOnly, TextTypeEnum textType)
        {
            switch (textType)
            {
                case TextTypeEnum.Normal:
                    return AddType(name, key, description, isHidden, isRequired, isReadOnly, ScienceTypeEnum.Text,
                                   new Dictionary<string, string> {{"texttype", "normal"}});
                case TextTypeEnum.Large:
                    return AddType(name, key, description, isHidden, isRequired, isReadOnly, ScienceTypeEnum.Text,
                                   new Dictionary<string, string> { { "texttype", "large" } });
                case TextTypeEnum.DropDown:
                    return AddType(name, key, description, isHidden, isRequired, isReadOnly, ScienceTypeEnum.Text,
                                   new Dictionary<string, string> { { "texttype", "dropdown" } });
                default:
                    throw new ArgumentOutOfRangeException("textType");
            }
        }

        public CollectionTypeCreationHelper AddValue(string name, string key, string description, bool isHidden, bool isRequired, bool isReadOnly, ValueTypeEnum valueType, string prefix, string unit, string format)
        {
            switch (valueType)
            {
                case ValueTypeEnum.Plain:
                    return AddType(name, key, description, isHidden, isRequired, isReadOnly, ScienceTypeEnum.Value,
                                   new Dictionary<string, string> {{"valuetype", "plain"}, {"format", format}});
                case ValueTypeEnum.PlainDropDown:
                    return AddType(name, key, description, isHidden, isRequired, isReadOnly, ScienceTypeEnum.Value,
                                   new Dictionary<string, string> {{"valuetype", "plaindropdown"}, {"format", format}});
                case ValueTypeEnum.Measurement:
                    return AddType(name, key, description, isHidden, isRequired, isReadOnly, ScienceTypeEnum.Value,
                                   new Dictionary<string, string>
                                       {
                                           {"valuetype", "measurement"},
                                           {"prefix", prefix},
                                           {"unit", unit},
                                           {"format", format}
                                       });
                case ValueTypeEnum.MeasurementDropDown:
                    return AddType(name, key, description, isHidden, isRequired, isReadOnly, ScienceTypeEnum.Value,
                                   new Dictionary<string, string>
                                       {
                                           {"valuetype", "measurementdropdown"},
                                           {"prefix", prefix},
                                           {"unit", unit},
                                           {"format", format}
                                       });
                default:
                    throw new ArgumentOutOfRangeException("valueType");
            }
        }

        public CollectionTypeCreationHelper AddDate(string name, string key, string description, bool isHidden, bool isRequired, bool isReadOnly, bool dateOnly)
        {
            return AddType(name, key, description, isHidden, isRequired, isReadOnly, ScienceTypeEnum.DateTime,
                                   new Dictionary<string, string>
                                       {
                                           {"datetype", dateOnly ? "date" : "datetime"}
                                       });
        }

        public CollectionTypeCreationHelper AddValueSet(string name, string key, string description, bool isHidden, bool isRequired, bool isReadOnly, bool isDownloadable, bool isGraphable, string xAxis, string yAxis, string xAxisLabel, string yAxisLabel, string format, bool isMeasurementType, string unit, string prefix)
        {
            return AddType(name, key, description, isHidden, isRequired, isReadOnly, ScienceTypeEnum.ValueSet,
                           new Dictionary<string, string>
                               {
                                   {"download", isDownloadable.ToString().ToLowerInvariant()},
                                   {"graph", isGraphable.ToString().ToLowerInvariant()},
                                   {"xaxis", xAxis},
                                   {"yaxis", yAxis},
                                   {"xaxislabel", xAxisLabel},
                                   {"yaxislabel", yAxisLabel},
                                   {"format", format},
                                   {"measurement", isMeasurementType.ToString().ToLowerInvariant()},
                                   {"unit",unit},
                                   {"prefix",prefix}
                               });
        }

        public CollectionTypeCreationHelper AddFiles(string name, string key, string description, bool isHidden, bool isRequired, bool isReadOnly)
        {
            return AddType(name, key, description, isHidden, isRequired, isReadOnly, ScienceTypeEnum.Files,
                           new Dictionary<string, string>());
        }

        public CollectionTypeCreationHelper AddVersionedFile(string name, string key, string description, bool isHidden, bool isRequired, bool isReadOnly)
        {
            return AddType(name, key, description, isHidden, isRequired, isReadOnly, ScienceTypeEnum.VersionedFile,
                           new Dictionary<string, string>());
        }

        public CollectionTypeCreationHelper AddParentLink(string name, string key, string description, bool isHidden, bool isRequired, bool isReadOnly, string collectionName)
        {
            return AddType(name, key, description, isHidden, isRequired, isReadOnly, ScienceTypeEnum.ParentLink,
                           new Dictionary<string, string> {{"collection", collectionName}});
        }

        public CollectionTypeCreationHelper AddChildLinks(string name, string key, string description, bool isHidden, bool isRequired, bool isReadOnly, string collectionName)
        {
            return AddType(name, key, description, isHidden, isRequired, isReadOnly, ScienceTypeEnum.ChildLinks,
                           new Dictionary<string, string> { { "collection", collectionName } });
        }

        public CollectionTypeCreationHelper AddBoolean(string name, string key, string description, bool isHidden, bool isRequired, bool isReadOnly)
        {
            return AddType(name, key, description, isHidden, isRequired, isReadOnly, ScienceTypeEnum.Boolean,
                           new Dictionary<string, string>());
        }

        private CollectionTypeCreationHelper AddType(string name, string key, string description, bool isHidden, bool isRequired, bool isReadOnly, ScienceTypeEnum type, IDictionary<string,string> settings)
        {
            var scienceType = new ScienceType
                                  {
                                      CreatedBy = _creatingUser,
                                      CreatedOn = _currentDate,
                                      Name = name,
                                      Type = type,
                                      Index = NextIndex(),
                                      Description = description,
                                      Key = key,
                                      Hidden = isHidden,
                                      Required = isRequired,
                                      Readonly = isReadOnly,
                                      Settings = settings
                                  };

            _dataSource.AddCollectionType(_collectionName, scienceType);

            return this;
        }

        private int NextIndex()
        {
            var query = _dataSource.QueryCollectionTypes(_collectionName).Select(x => x.Index);
            return !query.Any() ? 0 : query.Max() + 1;
        }
    }
}
